home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / clue.lha / clue / intrinsics.l < prev    next >
Text File  |  1989-07-12  |  58KB  |  1,571 lines

  1. ;;; -*- Mode:Lisp; Package:CLUEI; Syntax:COMMON-LISP; Base:10; Lowercase:T -*-
  2.  
  3. ;;;
  4. ;;;             TEXAS INSTRUMENTS INCORPORATED
  5. ;;;                  P.O. BOX 2909
  6. ;;;                   AUSTIN, TEXAS 78769
  7. ;;;
  8. ;;; Copyright (C) 1987 Texas Instruments Incorporated.
  9. ;;;
  10. ;;; Permission is granted to any individual or institution to use, copy, modify,
  11. ;;; and distribute this software, provided that this complete copyright and
  12. ;;; permission notice is maintained, intact, in all copies and supporting
  13. ;;; documentation.
  14. ;;;
  15. ;;; Texas Instruments Incorporated provides this software "as is" without
  16. ;;; express or implied warranty.
  17. ;;;
  18.  
  19. ;;;
  20. ;;; Change history:
  21. ;;;
  22. ;;;  Date    Author    Description
  23. ;;; -------------------------------------------------------------------------------------
  24. ;;; 07/08/87    LGO    Created
  25. ;;; 02/09/88    LGO    Change with-slots to conform to latest CLOS spec.
  26. ;;; 02/10/88    LGO    Change format of DEFACTION to be like DEFMETHOD.
  27. ;;; 02/10/88    LGO    Fix Initialization of screen-contact x,y,width,height,depth,border-width.
  28. ;;; 02/11/88    LGO    Replaced INITIALIZE methods with INITIALIZE-INSTANCE :AFTER methods.
  29. ;;; 02/11/88    LGO    Replaced crufty MENU-ITEM and MULTIPLE-MENU-ITEM contacts with BUTTON.
  30. ;;; 02/11/88    LGO    Upgraded the MENU contact to use BUTTON.
  31. ;;; 02/11/88    LGO    Added EXPORT's for all known externally accessable symbols
  32. ;;; 02/12/88    LGO    Replace screen-contact with root
  33. ;;; 02/15/88    LGO    Added POPUP-SHELL contact
  34. ;;; 02/17/88    LGO    Simplified arglist to REALIZE.  Ensured all ancestors are realized.
  35. ;;; 02/18/88    LGO    Added *contact* binding to apply-callback
  36. ;;; 02/18/88    LGO    Changed &key reversep arg in get-resource to &optional
  37. ;;; 02/18/88    KK    Changed arguments to event-matching functions
  38. ;;; 02/19/88    LGO    Removed all :class allocation for slots, since CLOS
  39. ;;;            doesn't re-allocate for children.
  40. ;;; 02/24/88    LGO    Re-worked event-spec check and match function argument lists.
  41. ;;; 02/26/88    LGO    Added the LABEL contact and made BUTTON use LABEL.
  42. ;;; 03/01/88    LGO    Renamed inside-contactp to inside-contact-p
  43. ;;; 03/01/88    LGO    Removed action-handled-p
  44. ;;; 03/01/88    LGO    Renamed *data-base* to *database*
  45. ;;; 03/07/88    LGO    Added the documentation contact resource
  46. ;;; 03/07/88    LGO    Added pseudo-event processing and the :double-click pseudo event
  47. ;;; 03/11/88    LGO    New event-spec syntax
  48. ;;; 03/14/88    LGO    Remove dependency on CLOS meta-classes.  
  49. ;;;            Gotta use make-contact instead of make-instance now
  50. ;;; 03/15/88    LGO    Removed window-manager properties from contact resource list
  51. ;;; 03/22/88    LGO    Re-wrote MAKE-CONTACT (takes advantage of initialize-instance optimizations)
  52. ;;; 03/23/88    LGO    Use WINDOW-ID for realized-p and destroyed-p
  53. ;;; 03/23/88    LGO    Made virtual-contact the parent of CONTACT
  54. ;;; 03/23/88    LGO    Removed contact COMPLETE-NAME and COMPLETE-CLASS slots.
  55. ;;; 03/24/88    LGO    When compress-motion, ignore enter-notify when
  56. ;;;            leave-notify for the same window is in the event queue.
  57. ;;; 03/28/88    LGO    Slots with :initargs are no-longer automatically made resources.
  58. ;;; 03/28/88    LGO    add clue-default-options method to contact initialization
  59. ;;; 03/29/88    LGO    Made the following methods functions:
  60. ;;;            change-geometry, change-priority, translate-event
  61. ;;; 03/29/88    LGO    Added explorer compiler optimization to change-geometry
  62. ;;; 03/29/88    LGO    Re-wrote add-resource
  63. ;;; 03/30/88    LGO    Use stringable-equal instead of eq in resource searches
  64. ;;; 04/07/88    LGO    Fixed virtual-menu use new menu code
  65. ;;; 04/07/88    LGO    Properly support :meta :super :hyper modifier states
  66. ;;; 04/15/88    LGO    Do event-parsing BEFORE class initializations.  Don't compute event mask until realized.
  67. ;;; 04/18/88    LGO    Move event-translations-mask computation into realize
  68. ;;; 04/18/88    LGO    Add :default init option
  69. ;;; 04/18/88    LGO    Export *parent*, don't export find-contact
  70. ;;; 04/19/88    LGO    Add &key to the lambda lists of manage-geometry, manage-priority,
  71. ;;;             display add-child and delete-child.
  72. ;;; 04/19/88    LGO    ------------- Version 13 sent to MIT ---------------
  73. ;;; 04/20/88    LGO    Only update event-mask when changed in add-event and delete-event.
  74. ;;; 04/20/88    LGO    Better trace & describe actions.
  75. ;;; 04/21/88    LGO    Ensure event-mask bits aren't lost by delete-event
  76. ;;; 04/25/88    LGO    Signal an error when argument types are wrong (can't be converted)
  77. ;;; 05/12/88    LGO    Change timers to have contact specific names, and alter timer arglists.
  78. ;;; 07/08/88    LGO    Change process-next-event to use the new xlib:event-cond macro.
  79. ;;; 07/11/88    LGO    Ensure all exported functions have doc strings.
  80. ;;; 07/13/88    LGO    Make change-geometry recall manage-geometry when accepting a compromise.
  81. ;;; 07/13/88    LGO    Make the default width/height zero, and check for zero width/height in realize.
  82. ;;; 07/15/88    LGO    Make event state-mask parsing consistent.
  83. ;;; 07/18/88    LGO    Add error checking to parse-event-spec
  84. ;;; 07/21/88    LGO    Fix bugs in popup menus
  85. ;;; 07/21/88    LGO    Fix bugs modal input
  86. ;;; 07/21/88    LGO    Change the contact-background slot to background.
  87. ;;; 07/21/88    LGO     Set window manager x/y properties properly for top level windows
  88. ;;; 07/28/88    LGO    Fix interactive-stream unread-char to use cluei:unread-character
  89. ;;;            instead of using a last-unread-character in the contact.
  90. ;;; 08/03/88    LGO    Fix misc. bugs in interactive stream.
  91. ;;; 08/05/88    LGO    Postpone geometry management to realize time, and  change-layout.
  92. ;;; 08/08/88    LGO    Replaced xlib::declare-values with (declare (values ...))
  93. ;;; 08/10/88    LGO    Removed explorer compiler optimization to change-geometry
  94. ;;; 08/10/88    LGO    change-geometry: accept requested change immediately if contact is unmanaged.
  95. ;;; 08/11/88    LGO    Re-wrote contact initialization to type-check/convert arguments to make-contact.
  96. ;;; 08/18/88    LGO    Replace managed-p slot with state.  Added update-state and re-worked realization.
  97. ;;;            Removed manage, unmanage, present, dismiss.
  98. ;;; 08/19/88    LGO    Added event-actions and fixed add-event to maintain event ordering.
  99. ;;; 08/22/88    LGO    Added conversion from card8 or string to cursor
  100. ;;; 08/29/88    LGO    Add the add-to-parent method, instead of doing a (typep x 'popup-shell) test.
  101. ;;; 09/19/88    LGO    Add :CLUE to the *features* list
  102.  
  103. #| To do:
  104.  
  105. 1. Handle reparenting events
  106. 2. Upgrade screen contacts to cooperate with window managers
  107.     a. fancy geometry manager
  108.     b. Check root for different parent window
  109. 3. Ensure :screen is a contact resource
  110.  
  111. 4. Things would run faster if some of the often used functions didn't used keyargs.
  112.    Candidates are xlib:create-window
  113.  
  114. 5. Finish implementation of multi-click button keysyms.
  115.  
  116. |#
  117.  
  118. (in-package 'cluei :use '(lisp xlib))
  119.  
  120. (export '(display-root ;; Setf'able
  121.       display-root-list
  122.       display-multipress-delay-limit
  123.       display-multipress-verify-p
  124.       *default-host*
  125.       *default-display*
  126.       *default-multipress-delay-limit*
  127.       *default-multipress-verify-p*       
  128.  
  129.       *parent*                ; Bound during contact initialization
  130.       open-contact-display
  131.       
  132.       basic-contact
  133.       contact
  134.       make-contact
  135.       ;; Contact slots:
  136.       display
  137.       parent
  138.       complete-name
  139.       complete-class
  140.       callbacks
  141.       event-translations
  142.       state
  143.       sensitive
  144.       compress-motion
  145.       compress-exposures
  146.       x y width height
  147.       border-width
  148.       background
  149.       depth
  150.       event-mask
  151.       id
  152.       plist
  153.       
  154.       ;; Contact slot accessors:
  155.       contact-background
  156.       contact-border-width
  157.       contact-callbacks
  158.       contact-compress-exposures
  159.       contact-compress-motion
  160.       contact-depth
  161.       contact-display
  162.       contact-event-mask
  163.       contact-height
  164.       contact-parent
  165.       contact-sensitive
  166.       contact-state
  167.       contact-width
  168.       contact-x
  169.       contact-y
  170.       
  171.       composite
  172.       children focus shells
  173.       composite-children
  174.       composite-focus
  175.       composite-shells
  176.       
  177.       destroy
  178.       
  179.       contact-complete-name
  180.       contact-complete-class
  181.       contact-name
  182.       display-name
  183.       display-class
  184. ;;      find-contact
  185.       ancestor-p
  186.       realized-p
  187.       destroyed-p
  188.       mapped-p
  189.       top-level-p
  190.       managed-p
  191.       sensitive-p
  192.       event-mask  ;; Setf'able
  193.       resource
  194.       update-state
  195.       initialize-geometry 
  196.       present
  197.       dismiss
  198.       realize
  199.       display
  200.  
  201.       add-callback
  202.       apply-callback
  203.       callback-p
  204.       delete-callback
  205.       *contact*
  206.       
  207.       root
  208.       contact-root
  209.       contact-screen
  210.  
  211.       read-character
  212.       unread-character
  213.       listen-character
  214.       append-characters
  215.       clear-characters
  216.       
  217.       add-child
  218.       delete-child
  219.       previous-sibling
  220.       next-sibling
  221.       change-priority
  222.       manage-priority
  223.       accept-focus-p
  224.       move-focus
  225.       change-layout
  226.       change-geometry
  227.       preferred-size
  228.       move
  229.       resize
  230.       manage-geometry
  231.  
  232.       
  233.       spring-loaded
  234.       shadow-width
  235.  
  236.       contact-constraints
  237.       contact-constraint
  238.       class-constraints))
  239.  
  240. (pushnew :CLUE *features*)
  241.  
  242. ;;;-----------------------------------------------------------------------------
  243. ;;; Extend the xlib:display object for CLUE slots
  244.  
  245. (defmacro display-root-list (display)
  246.   "Returns a list of root contacts in the order given by xlib:open-display."
  247.   `(the list (getf (xlib:display-plist ,display) 'root-list)))
  248.  
  249. (defun display-root (display &optional number)
  250.   "Returns the root of the display specified by the screen NUMBER."
  251.   (if number
  252.       (nth number (display-root-list display))
  253.     (getf (xlib:display-plist display) 'default-root)))
  254.  
  255. (defsetf display-root (display) (screen)
  256.   `(setf (getf (xlib:display-plist ,display) 'default-root) ,screen))
  257.  
  258. (defmacro before-actions (display)
  259.   "Returns the alist of functions to call before event processing with arguments."
  260.   `(the list (getf (xlib:display-plist ,display) 'event-before-handlers)))
  261.  
  262. (defmacro timer-queue (display)
  263.   "Returns the list of display timer structures."
  264.   `(the list (getf (xlib:display-plist ,display) 'timer-queue)))
  265.  
  266. (defmacro display-keyboard-buffer (display)
  267.   "Returns the buffer used for keyboard input by all stream contacts on DISPLAY."
  268.   `(getf (xlib:display-plist ,display) 'keyboard-buffer))
  269.  
  270. (defmacro display-modifier-translate (display)
  271.   "Returns the translations used for keyboard input by all stream contacts in DISPLAY."
  272.   `(getf (xlib:display-plist ,display) 'modifier-translate))
  273.  
  274. (defmacro display-update-flag (display)
  275.   "Returns the flag used to indicate when update-state has work to do."
  276.   `(getf (xlib:display-plist ,display) 'update-flag))
  277.  
  278. (defun display-mode-stack (display)
  279.   "Returns the mode-stack of the DISPLAY. The current input mode of a contact-display 
  280. is given by its mode-stack. The mode-stack is an alist containing entries of the form 
  281. (contact mode-type restrict-action . args)."
  282.   (getf (display-plist display) 'mode-stack))
  283.  
  284. (defsetf display-mode-stack (display) (stack)
  285.   `(setf (getf (display-plist ,display) 'mode-stack) ,stack))
  286.  
  287. (defun display-multipress-delay-limit (display)
  288.   "Reject a multipress that occurs more than this many milliseconds after initial press event."
  289.   (getf (display-plist display) 'multipress-delay-limit))
  290.  
  291. (defsetf display-multipress-delay-limit (display) (msec)
  292.   `(setf (getf (display-plist ,display) 'multipress-delay-limit) ,msec))
  293.  
  294. (defun display-multipress-verify-p (display)
  295.   "When true, verify timeout of multipress events by requesting a timestamp."
  296.   (getf (display-plist display) 'multipress-verify-p))
  297.  
  298. (defsetf display-multipress-verify-p (display) (flag)
  299.   `(setf (getf (display-plist ,display) 'multipress-verify-p) ,flag))
  300.  
  301. (defun display-name (display)
  302.   "Returns the application resource name associated with the display."
  303.   (getf (display-plist display) 'resource-name))
  304.  
  305. (defsetf display-name (display) (name)
  306.   `(setf (getf (display-plist ,display) 'resource-name) ,name))
  307.  
  308. (defun display-class (display)
  309.   "Returns the application resource class associated with the display."
  310.   (getf (display-plist display) 'resource-class))
  311.  
  312. (defsetf display-class (display) (class)
  313.   `(setf (getf (display-plist ,display) 'resource-class) ,class))
  314.  
  315.  
  316. ;;;-----------------------------------------------------------------------------
  317. ;;; CLUE applications call OPEN-CONTACT-DISPLAY to connect to an X server.
  318. ;;; The object returned by OPEN-CONTACT-DISPLAY is a CLX DISPLAY object that also contains
  319. ;;; the before and after event-handler lists, and the application keyboard buffer
  320. ;;;-----------------------------------------------------------------------------
  321.  
  322. (defvar *default-host* nil)
  323. (defvar *default-display* 0)
  324.  
  325. (defvar *default-multipress-delay-limit* 250
  326.   "Default value for display-multipress-delay-limit.")
  327.  
  328. (defvar *default-multipress-verify-p* t
  329.   "Default value for display-multipress-verify-p.")
  330.  
  331. (defun open-contact-display (application-name
  332.                  &key authorization-data authorization-name
  333.                       before-actions class (default-screen 0)
  334.                   display host protocol (root-class 'root))
  335.   "Create and open a new contact-display."
  336.   (declare (type xlib:stringable application-name host)
  337.        (type (or null integer) display)
  338.        (type (or null (integer 0)) default-screen)
  339.        (values contact-display))
  340.   (declare (ignore protocol));; not included because of CLX bugs
  341.   
  342.   (unless *default-host* ;; Set default if none defined
  343.     (setq *default-host* host))
  344.   (let ((disp (xlib:open-display (or host *default-host*)
  345.          :display (or display *default-display*)
  346. ;;         :protocol protocol ;; not included because of CLX bugs
  347.          :authorization-name authorization-name
  348.          :authorization-data authorization-data))
  349.     (display-class (or class application-name)))
  350.  
  351.     ;; Initialize resource name and class
  352.     (setf (display-name disp)  application-name
  353.       (display-class disp) display-class)
  354.     
  355.     ;; Create a root contact for each screen of the display
  356.     (let ((i 0)
  357.       roots)
  358.       (dolist (screen (xlib:display-roots disp))
  359.     (let ((name (intern (format nil "SCREEN-~d" i) 'keyword)))      
  360.       (push (make-contact
  361.           root-class
  362.           :display disp
  363.           :screen screen
  364.           :parent nil
  365.           :name name
  366.           :complete-name  (list application-name name)
  367.           :complete-class (list display-class root-class))
  368.         roots))
  369.     (incf i))
  370.  
  371.       ;; Initialize root list and default root
  372.       (setf (display-root-list disp) (nreverse roots)
  373.         (display-root disp)      (nth default-screen (display-root-list disp))))        
  374.     
  375.     ;; Function to call BEFORE event handling
  376.     (setf (before-actions disp) before-actions)
  377.     
  378.     ;; List of characters from the keyboard
  379.     (setf (display-keyboard-buffer disp) nil)
  380.  
  381.     ;; Initialize multipress controls
  382.     (setf (display-multipress-delay-limit disp) *default-multipress-delay-limit*
  383.       (display-multipress-verify-p disp)    *default-multipress-verify-p*)
  384.     
  385.     disp))
  386.  
  387.  
  388. ;;;-----------------------------------------------------------------------------
  389. ;;; Basic CONTACT class
  390.  
  391. (defcontact basic-contact (xlib:window)
  392.   ((display            :initarg :display
  393.                :reader contact-display)
  394.    
  395.    (parent             :initarg :parent
  396.                :reader contact-parent)
  397.    
  398.    (name               :type symbol
  399.                :initarg :name
  400.                :initform :unnamed
  401.                :reader contact-name)
  402.    
  403.    (callbacks          :type list
  404.                :reader contact-callbacks
  405.                :initform nil)
  406.    
  407.    (event-translations :type list
  408.                :initform nil)
  409.    
  410.    (event-mask         :type (or null event-mask) ;; Converted to mask32 after realization. 
  411.                :initform #.(make-event-mask :exposure)
  412.                :accessor contact-event-mask)
  413.    
  414.    (state              :initform :mapped
  415.                :type (member :withdrawn :managed :mapped)
  416.                :accessor contact-state)
  417.    
  418.    (sensitive          :initform :on
  419.                :type (member :off :on)
  420.                :accessor contact-sensitive)
  421.    
  422.    (x                  :type int16
  423.                :initform 0
  424.                :reader contact-x)
  425.    
  426.    (y                  :type int16
  427.                :initform 0
  428.                :reader contact-y)
  429.    
  430.    (width              :type card16
  431.                :initform 0
  432.                :reader contact-width)
  433.    
  434.    (height             :type card16
  435.                :initform 0
  436.                :reader contact-height)
  437.    
  438.    (border-width       :type card16
  439.                :initform 1
  440.                :reader contact-border-width)
  441.    
  442.    ;; Class allocated slots
  443.    (compress-motion    :initform :on :type (member :off :on)
  444.                :reader contact-compress-motion
  445.                :allocation :class)
  446.    
  447.    (compress-exposures :initform :off :type (member :off :on)
  448.                :reader contact-compress-exposures
  449.                :allocation :class
  450.                ))
  451.   (:documentation "Basic contact using parent's window")
  452.   (:resources
  453.     (screen :type (or null card8))            ;Selects screen when parent is a display
  454.     ;; Slots
  455.     name
  456.     callbacks
  457.     event-translations
  458.     event-mask
  459.     state
  460.     sensitive
  461.     x y width height border-width
  462.     ))
  463.  
  464. (defcontact contact (basic-contact)
  465.   ((background :type (or (member :none :parent-relative) pixel pixmap)
  466.            :initform :parent-relative :accessor contact-background)
  467.    (depth :type card16 :initform 0 :reader contact-depth)
  468.    (initialization :type (or (member :destroy) list))    ; Internal slot for window initialization and destruction
  469.    )
  470.   (:documentation "Basic contact")
  471.   (:resources
  472.     (documentation :type (or list string))
  473.  
  474.     ;; Slots
  475.     (background :type (or (member :none :parent-relative) pixel pixmap))
  476.     (depth :type card16)
  477.     
  478.     ;; Create-window options
  479. ;;    (backing-pixel :type (or null pixel))
  480. ;;    (backing-planes :type (or null pixel))
  481.     (backing-store :type (or null (member :not-useful :when-mapped :always)))
  482. ;;    (bit-gravity :type (or null bit-gravity))
  483.     (border :type (or null (member :copy) pixel pixmap))
  484. ;;    (class :type (member :copy :input-output :input-only) :initform :copy)
  485. ;;    (colormap :type (or null (member :copy) colormap))
  486.     (cursor :type (or null (member :none) cursor))
  487. ;;    (do-not-propagate-mask :type (or null device-event-mask))
  488. ;;    (gravity :type (or null win-gravity))
  489.     (override-redirect :type (or null (member :on :off)))
  490.     (save-under :type (or null (member :on :off)))
  491. ;;    (visual :type (or (member :copy) card29) :initform :copy)
  492.     )
  493.   (:documentation "A basic CLUE window which all CLUE contacts use"))
  494.  
  495. (defcontact composite (contact)
  496.   ((children :initform nil
  497.          :type list
  498.          :reader composite-children)
  499.    (focus    :initform nil
  500.          :type (or null contact)
  501.          :reader composite-focus)
  502.    (shells   :type list
  503.          :initform nil
  504.          :reader composite-shells))
  505.   (:resources
  506.     (event-mask :type (or null event-mask) :initform #.(make-event-mask))
  507.     (focus-name :type symbol))
  508.   (:documentation "A basic CLUE contact with children"))
  509.  
  510.  
  511.  
  512.  
  513. ;;;-----------------------------------------------------------------------------
  514. ;;; UTILITY FUNCTIONS
  515.  
  516. (defmethod print-object ((instance contact) stream)
  517.   (let ((name (if (slot-boundp instance 'name)
  518.           (contact-name instance)
  519.           :uninitialized)))
  520.     #+lispm
  521.     (si:printing-random-object (instance stream)
  522.       (princ (class-name-of instance) stream)
  523.       (write-char #\space stream)
  524.       (princ name stream))
  525.     #-lispm
  526.     (progn
  527.       (write-string "#<" stream)
  528.       (princ (class-name-of instance) stream)
  529.       (write-char #\space stream)
  530.       (princ name stream)
  531.       (write-char #\> stream))))
  532.  
  533. (defun contact-complete-name (contact &optional nconc-name)
  534.   ;; Return the complete name for contact
  535.   ;; when present, nconc-name is put at the END of the name list.
  536.   ;; This speeds getting the complete name of a contact given its parent and name.
  537.   (let ((result (if nconc-name
  538.             (list (contact-name contact) nconc-name)
  539.             (list (contact-name contact)))))
  540.     
  541.     ;; Prepend names up to contact root
  542.     (do ((parent (contact-resource-parent contact) (contact-resource-parent parent)))
  543.     ((null parent))
  544.       (push (contact-name parent) result))
  545.     
  546.     ;; Prepend application name
  547.     (push (display-name (contact-display contact)) result)
  548.     result))
  549.  
  550. (defun contact-complete-class (contact &optional nconc-class)
  551.   ;; Return the complete class for contact
  552.   ;; when present, nconc-class is put at the END of the class list.
  553.   ;; This speeds getting the complete class of a contact given its parent and class.
  554.   (let ((result (if nconc-class
  555.             (list (class-name-of contact) nconc-class)
  556.             (list (class-name-of contact)))))
  557.     
  558.     ;; Prepend classes up to contact root
  559.     (do ((parent (contact-resource-parent contact) (contact-resource-parent parent)))
  560.     ((null parent))
  561.       (push (class-name-of parent) result))
  562.     
  563.     ;; Prepend application class
  564.     (push (display-class (contact-display contact)) result)
  565.     result))
  566.  
  567.  
  568. (defmethod contact-resource-parent ((contact contact))
  569.   (slot-value contact 'parent))
  570.  
  571. (defun find-contact (parent &key name class)
  572.   "Return the contact in PARENT with NAME and CLASS.
  573.  If name or class is NIL, it is ignored."
  574.   (declare (type (or composite display) parent)
  575.        (type symbol name class)
  576.        (values (or null contact)))
  577.   (labels ((search (list name class)
  578.          (dolist (contact list)
  579.            (when (and (or (null name) (eq name (contact-name contact)))
  580.               (or (null class) (eq class (class-name-of contact))))
  581.          (return-from search contact)))
  582.          (dolist (contact list)
  583.            (let* ((children (composite-children contact))
  584.               (result (and children (search children name class))))
  585.          (when result (return-from search result))))))
  586.     (etypecase parent
  587.       (display   (search (display-root-list parent) name class))
  588.       (composite (search (composite-children parent) name class)))))
  589.  
  590. (defun ancestor-p (child parent)
  591.   "Returns T when CHILD is a descendant of PARENT"
  592.   (do ((p (contact-parent child) (contact-parent p)))
  593.       ((null p))
  594.     (when (eq p parent) (return t))))
  595.  
  596. (defun realized-p (contact)
  597.   "Returns T when contact's window is created and not destroyed"
  598.   (plusp (window-id contact)))
  599.  
  600. (defun destroyed-p (contact)
  601.   "Returns T when contat's window is (being) destroyed"
  602.   (minusp (window-id contact)))
  603.  
  604. (proclaim '(inline managed-p))
  605. (defun managed-p (contact)
  606.   "Returns non-nil when contact is geometry managed by its parent"
  607.   (NOT (EQ (contact-state contact) :withdrawn)))
  608.  
  609. (defun mapped-p (contact)
  610.   "Returns non-nil when contact is mapped"
  611.   (eq (contact-state contact) :mapped))
  612.  
  613. (defun visible-p (contact)
  614.   "Returns T when contact is visible (fully or partially)"
  615.   (and (realized-p contact)
  616.        (mapped-p contact)
  617.        t) ;; Put in fancy visibilty testing if deemed necessary
  618.   )
  619.  
  620. (defun top-level-p (contact)
  621.   "Returns T when CONTACT is a top-level window
  622.  (i.e. under control of a window manager)"
  623.   (and (contact-parent contact) ;; Not a root
  624.        (null (contact-parent (contact-parent contact)))))
  625.  
  626. (defmethod (setf contact-sensitive) (value (self contact))
  627.   ;; Redisplay when changing sensitive
  628.   (declare (type (member :off :on) value))
  629.   (check-type value (member :off :on))
  630.   (with-slots ((contact-sensitive sensitive)) self
  631.     (let ((old contact-sensitive))
  632.       (setf contact-sensitive value)
  633.       (when (and (not (eq old value))
  634.          (visible-p self))
  635.     (with-slots (x y width height) self
  636.       (display self x y width height))))))
  637.  
  638. (defun sensitive-p (contact)
  639.   "Returns T when a contact and all its ancestors are sensitive
  640.    If there's a mode-stack, the contact, or one of its ancestors,
  641.    must be in the current mode."
  642.   (declare (inline sensitive-p))
  643.   (do ((p contact (contact-parent p)))
  644.       ((null p) t)
  645.     (when (eq (slot-value (the contact p) 'sensitive) :off) (return nil))))
  646.  
  647. (defmethod (setf contact-event-mask) (mask (contact contact))
  648.   (when (realized-p contact)
  649.     (setf (window-event-mask contact) mask))
  650.   (setf (slot-value (the contact contact) 'event-mask)
  651.     (xlib::encode-event-mask mask)))
  652.  
  653. (defmethod (setf contact-background) (background (contact contact))
  654.   (declare (type contact contact)
  655.        (type (or (member :none :parent-relative) pixel pixmap) background))
  656.   (when (realized-p contact)
  657.     (setf (window-background contact) background))
  658.   (setf (slot-value (the contact contact) 'background) background))
  659.  
  660.  
  661. ;;;-----------------------------------------------------------------------------
  662. ;;; CONSTRAINT RESOURCES
  663.  
  664.  
  665. (defmacro contact-constraints (contact)
  666.   "Return the list of constraint resource values for the CONTACT."
  667.   `(getf (window-plist ,contact) 'constraints))
  668.  
  669.  
  670. (defmacro contact-constraint (contact name)
  671.   "Return the value of the constraint resource NAME for the CONTACT."
  672.   `(getf (contact-constraints ,contact) (intern (symbol-name ,name) 'keyword)))
  673.  
  674.  
  675. (defun class-constraints (class &optional full-p)
  676.   "Return the constraint resource specification list for the given CLASS.
  677. If FULL-P is true, then the full list is returned; otherwise, a list of names is returned."
  678.   (let ((full-list (clue-constraints class)))
  679.     (if full-p
  680.     full-list
  681.     (mapcar #'first full-list))))
  682.  
  683.  
  684. ;;;-----------------------------------------------------------------------------
  685. ;;; Contact creation
  686.  
  687.  
  688. (defun make-contact (class-name &rest options)
  689.   "Make a contact of type CLASS-NAME, initializing with OPTIONS or from the resource database.
  690.    Every contact must have a :PARENT."
  691.   (apply #'make-instance class-name
  692.      :allow-other-keys t    ;; temporary until we find a better fix
  693.      (default-options class-name options)))
  694.  
  695. (defmethod default-options ((class-name t) options)
  696.   (declare (ignore options))
  697.   ;; An (eql class-name) method should be defined by defcontact.
  698.   (error "~s isn't the name of a contact subclass" class-name))
  699.  
  700.  
  701. (defun get-contact-resource-table (class-name parent initargs)
  702.   ;; Get the resource database table
  703.   ;;
  704.   ;; Note: This is called with a null parent when class-name is ROOT, in which case
  705.   ;;       this will lose unless INITARGS contains :complete-name and :complete-class.
  706.   (declare (special *database*))
  707.   (get-search-table
  708.       *database*
  709.       (or (getf initargs :complete-name)
  710.       (contact-complete-name parent (or (getf initargs :name)
  711.                         class-name)))
  712.       (or (getf initargs :complete-class)
  713.       (contact-complete-class parent class-name))))
  714.  
  715. (defmethod initialize-instance :after ((self basic-contact)
  716.                        &rest initargs
  717.                        &key resource-table defaults
  718.                        &allow-other-keys)  
  719.   (with-slots ((contact-name name)           
  720.            (contact-disp display)
  721.            (contact-parent parent)
  722.            (contact-event-translations event-translations)
  723.            (contact-event-mask event-mask)) self
  724.  
  725.     ;; Complete slot resource initialization
  726.     (initialize-resource-slots self resource-table defaults)
  727.  
  728.     ;; Initialize constraint resources
  729.     (when contact-parent
  730.       (setf (contact-constraints self)
  731.         (initialize-constraints contact-parent initargs resource-table)))
  732.       
  733.     ;; Initialize name to class name by default
  734.     (when (eq contact-name :unnamed)
  735.       (setf contact-name (class-name-of self)))
  736.     
  737.     ;; Parse event-translations
  738.     (setf contact-event-translations
  739.       (mapcar #'parse-event-spec contact-event-translations)
  740.       contact-event-mask
  741.       (xlib::encode-event-mask contact-event-mask))
  742.  
  743.     ;; Add to composition hierarchy
  744.     (when contact-parent ; root contact's don't have a parent
  745.       (setf contact-disp (contact-display contact-parent))
  746.       (add-to-parent self))))
  747.  
  748.  
  749.  
  750. (defmethod initialize-instance :after ((self contact) &rest initargs)
  751.   (declare (type list initargs))
  752.   
  753.   (setf (display-update-flag (contact-display self)) t)
  754.  
  755.   ;; Save initargs
  756.   (let ((options (copy-list initargs)))
  757.     ;; Allow resource-table to be GC'd
  758.     (remf options :resource-table)     
  759.     (setf (slot-value (the contact self) 'initialization) options))
  760.  
  761.   ;; Default depth from parent
  762.   (with-slots (depth parent) self
  763.     (when (zerop depth)
  764.       (setf depth (if parent
  765.               (contact-depth parent)
  766.               (screen-root-depth (contact-screen self)))))))
  767.  
  768. ;;;-----------------------------------------------------------------------------
  769. ;;; CALLBACKS
  770.  
  771. (defvar *contact* nil "Bound to the contact whose callback is being invoked.")
  772.  
  773. (proclaim '(inline callback-p))
  774. (defun callback-p (contact callback-name)
  775.   (cdr (assoc callback-name (slot-value contact 'callbacks) :test #'eq)))
  776.  
  777. (defun function-equal-p (f g)
  778.   (eq (if (symbolp f) (symbol-function f) f)
  779.       (if (symbolp g) (symbol-function g) g)))
  780.  
  781. (defun add-callback (contact name function &rest args)
  782.   "Associate CONTACT callback NAME with the given FUNCTION and ARGS."
  783.   (with-slots (callbacks) contact
  784.     (let ((functions    (assoc name callbacks :test #'eq))
  785.       (new-function (list* function (copy-list args))))
  786.       (if functions
  787.       ;; Append behind any previous functions for this callback
  788.       (rplacd functions (nconc (delete function (rest functions)
  789.                      :test #'function-equal-p
  790.                      :key #'first
  791.                      :count 1)
  792.                    (list new-function)))
  793.  
  794.       ;; Else add first callback function
  795.       (push (list name new-function) callbacks))
  796.       name)))
  797.  
  798. (defun delete-callback (contact name &optional function)
  799.   "Disassociate the given FUNCTION and its args from the CONTACT callback NAME.
  800.    If no FUNCTION is given, then all callback functions are deleted."
  801.   (with-slots (callbacks) contact
  802.     (let ((functions (assoc name callbacks :test #'eq)))
  803.       (when functions
  804.     (let ((new-functions (when function
  805.                    (delete function (rest functions)
  806.                        :test #'function-equal-p
  807.                        :key #'first
  808.                        :count 1))))
  809.       (if new-functions
  810.           (rplacd functions new-functions)
  811.           (setf callbacks (delete name callbacks
  812.                       :test #'eq
  813.                       :key #'first)))))))
  814.   name)
  815.  
  816.  
  817. (defmacro apply-callback (contact name &rest args)
  818.   "Invoke callback functions associated with NAME for CONTACT,
  819.    using ARGS followed by the callback arguments. *contact* is
  820.    bound to CONTACT during execution of the functions."
  821.   (let ((functions (gensym))
  822.     (instance  (gensym)))
  823.     `(let* ((,instance  ,contact)
  824.         (,functions (callback-p ,instance ,name)))
  825.        
  826.     (when ,functions
  827.       (let ((*contact* ,instance))
  828.         (catch :abort-callback
  829.           (do* ((functions ,functions         (rest functions))
  830.             (function  (first ,functions) (first functions)))
  831.            
  832.            ((null (rest functions))
  833.             ;; Return value(s) of last callback function
  834.             (apply (first function) ,@args (rest function)))
  835.         
  836.         (apply (first function) ,@args (rest function)))))))))
  837.  
  838.  
  839.  
  840. ;;;-----------------------------------------------------------------------------
  841. ;;; Basic contact methods
  842.  
  843. (defmethod add-to-parent ((self basic-contact))
  844.   (add-child (contact-parent self) self))
  845.  
  846. (defmethod (setf contact-parent) (new-parent (contact contact) &key x y)
  847.   (let ((c (or (when (destroyed-p contact) contact)
  848.            (when (destroyed-p new-parent) new-parent))))
  849.     (when c
  850.       (error "~s is being destroyed." c)))
  851.   
  852.   (with-slots (parent) contact
  853.     
  854.     ;; Forestall any MATCH errors from reparent-window
  855.     (unless (eq (contact-screen new-parent) (contact-screen parent)) 
  856.       (error "New parent screen (~s) must be the same as old parent screen (~s)."
  857.          (contact-screen new-parent) (contact-screen parent)))
  858.     (when (eq new-parent contact) 
  859.       (error "Cannot reparent ~s to itself." contact))
  860.     (when (ancestor-p new-parent contact) 
  861.       (error "New parent ~s is already a descendant of ~s." new-parent contact))
  862.     (when (and (eq (contact-background contact) :parent-relative)
  863.            (/= (contact-depth contact) (contact-depth new-parent))) 
  864.       (error "New parent depth (~s) must be the same as contact depth (~s)."
  865.          (contact-depth new-parent) (contact-depth contact)))
  866.     
  867.     (let ((actual-state (contact-state contact))
  868.       (new-x        (or x (contact-x contact)))
  869.       (new-y        (or y (contact-y contact))))
  870.       
  871.       ;; Unmap and unmanage until reparented
  872.       (setf (contact-state contact) :withdrawn)
  873.       
  874.       ;; Tell server to reparent window
  875.       (reparent-window contact new-parent new-x new-y)
  876.       
  877.       ;; Update contact hierarchy
  878.       (delete-child parent contact)
  879.       (setf parent new-parent)
  880.       (add-child new-parent contact)
  881.       
  882.       ;;Restore state
  883.       (setf (contact-state contact) actual-state))))
  884.  
  885.  
  886. (defmethod (setf contact-state) (state (contact contact))
  887.   (declare (special *all-children-mapped-p*))
  888.   
  889.   (check-type state (member :withdrawn :managed :mapped))
  890.   
  891.   (let ((old-state (slot-value (the contact contact) 'state)))
  892.     (unless (eq old-state state)
  893.       (setf (slot-value (the contact contact) 'state) state)
  894.       (if (realized-p contact)
  895.       ;; When realized, change state immediately
  896.       (progn 
  897.         (when (or (eq old-state :withdrawn)
  898.               (eq state     :withdrawn))
  899.           ;; Let parent react to transition to/from g.mgmt.
  900.           (change-layout (contact-parent contact) contact))
  901.         
  902.         (if (eq state :mapped)
  903.         
  904.         ;; Was unmapped, now mapped
  905.         (unless (boundp '*all-children-mapped-p*)
  906.           (map-window contact))
  907.         
  908.         (when (eq old-state :mapped)
  909.           ;; Was mapped, now unmapped
  910.           (unmap-window contact))))
  911.       
  912.       ;; Not realized, let UPDATE-STATE do the work
  913.       (setf (display-update-flag (contact-display contact)) t))))
  914.   state)
  915.  
  916.  
  917.  
  918. ;; Compatibility hack - remove soon
  919. (defun present (contact) (setf (contact-state contact) :mapped))
  920.  
  921. ;; Compatibility hack - remove soon
  922. (defun dismiss (contact &optional (unmanage-p t))
  923.   (if unmanage-p 
  924.       (setf (contact-state contact) :withdrawn)
  925.     (setf (contact-state contact) :managed)))
  926.    
  927. (defun update-state (display)
  928.   (when (display-update-flag display)
  929.     (dolist (root (display-root-list display))
  930.       (update-tree root))
  931.     (setf (display-update-flag display) nil)))
  932.  
  933. (defmethod update-tree ((composite composite))
  934.   ;; Search for a composite with an unrealized child and update it.
  935.   (let ((children (composite-children composite)))
  936.     (if (dolist (child children)
  937.       (when (and (not (realized-p child)) (managed-p child))
  938.         (return t)))
  939.     
  940.     (progn
  941.       (initialize-geometry composite)
  942.       (dolist (child children)
  943.         (when (and (not (realized-p child)) (managed-p child))
  944.           (realize child)
  945.           (realize-state child))))
  946.     
  947.     ;; No unrealized children here, continue the search lower down
  948.     (dolist (child children)
  949.       (when (realized-p child)
  950.         (update-tree child))))))
  951.  
  952. (defmethod update-tree ((contact contact))
  953.   ;; Do nothing
  954.   )
  955.  
  956.  
  957. (defmethod display ((contact basic-contact) &optional x y width height &key)
  958.   "Display self on server"
  959.   ;; This function needs to be over-ridden by the subclasses
  960.   (declare (ignore x y width height))
  961.   contact ;; not used
  962.   )
  963.  
  964.  
  965. ;;;-----------------------------------------------------------------------------
  966. ;;; REALIZE - create the X window associated with a contact
  967.  
  968. (defmethod realize ((contact contact))
  969.   "Create the Window for CONTACT.
  970.    This is a method to allow contacts to specialize the options.
  971.    Applications should call PRESENT."
  972.   (with-slots (parent x y width height border-width
  973.               event-mask background depth
  974.               initialization) contact
  975.  
  976.     ;; Ensure the parent is realized
  977.     (unless (realized-p parent)
  978.       (error "Attempt to realize ~s whose parent isn't realized" contact))
  979.  
  980.     ;; Ensure width/height initialized
  981.     (unless (and (plusp width) (plusp height))
  982.       (error "Width and Height have not been initialized for ~s" contact))
  983.  
  984.     ;; Calculate event-mask
  985.     (let ((mask (logior event-mask (compute-contact-event-mask contact))))
  986.       (when (top-level-p contact) ;; add structure-notify to top-level windows
  987.     (setq mask (logior mask #.(make-event-mask :structure-notify))))
  988.       (setf event-mask mask))
  989.  
  990.     ;; Create the contact window
  991.     (apply #'xlib:create-window
  992.        :window contact
  993.        :parent parent
  994.        :x x :y y :width width :height height
  995.        :border-width border-width
  996.        :event-mask event-mask
  997.        :background background
  998.        :depth depth
  999.        :allow-other-keys t initialization)        
  1000.  
  1001.     (let* ((documentation (getf initialization :documentation)))
  1002.       (when documentation
  1003.     (setf (window-documentation contact) documentation)))
  1004.  
  1005. ;; Keep initialiation around for awhile, it's useful for debugging
  1006. ;;    (setf initialization nil) ;; Give initialization list to the garbage collector
  1007.     ))
  1008.  
  1009.  
  1010. (defmethod realize :after ((contact composite))
  1011.   ;; Default focus from the :focus-name initialization
  1012.   (with-slots (initialization focus) contact 
  1013.     (let ((focus-name (getf initialization :focus-name)))
  1014.       (when (and focus-name (not focus))
  1015.     (setf focus (find-contact contact :name focus-name)))))
  1016.   
  1017.   ;; Map children here, to ensure the composite is mapped AFTER its children
  1018.   ;; This eliminates the screen flash that would happen if children were
  1019.   ;; mapped on top of a visible parent.
  1020.   (let* ((children (composite-children contact))
  1021.      (*all-children-mapped-p*
  1022.        (dolist (child children t)
  1023.          (unless (mapped-p child)
  1024.            (return nil)))))
  1025.     (declare (special *all-children-mapped-p*))
  1026.     
  1027.     ;; Recursively realize all managed children of COMPOSITE
  1028.     ;; Note: by definition, all children are unrealized
  1029.     (dolist (child children)
  1030.       (when (managed-p child)
  1031.     (realize child)
  1032.     (realize-state child)))
  1033.     
  1034.     ;; Map all children at once, if possible
  1035.     (when *all-children-mapped-p*
  1036.       (map-subwindows contact))))
  1037.  
  1038.  
  1039. (defmethod initialize-geometry ((composite composite))
  1040.   ;; Negotiate initial managed geometry from the bottom up
  1041.   (declare (type composite composite))
  1042.   (let (unrealized-child-exists-p)
  1043.  
  1044.     ;; Recursively descend to initialize-geometry for all unrealized managed children
  1045.     (dolist (child (composite-children composite))            
  1046.       (when (and (not (realized-p child)) (managed-p child))
  1047.     (setq unrealized-child-exists-p t)
  1048.     (initialize-geometry child)))
  1049.  
  1050.     ;; Optimization: don't bother to change layout unless necessary
  1051.     (when unrealized-child-exists-p
  1052.       (change-layout composite))))
  1053.  
  1054. (defmethod initialize-geometry ((contact contact))
  1055.   ;; Do nuthin'
  1056.   )
  1057.  
  1058. (defun realize-state (contact)
  1059.   "Make the initial contact-state of a newly-realized CONTACT effective."
  1060.   (multiple-value-bind (old-state new-state) (initial-state-transition contact)
  1061.     (when old-state
  1062.       ;; Problem:  This is a special case because the value of state slot after
  1063.       ;;           initialization is not yet in effect and doesn't reflect reality.
  1064.       ;; Solution: Temporarily set initial value of state slot to reality (i.e. old-state)     
  1065.       ;;           so that (setf contact-state) will take effect correctly.
  1066.       (setf (slot-value (the contact contact) 'state) old-state)
  1067.       (setf (contact-state contact) new-state))))
  1068.  
  1069. (defmethod initial-state-transition ((contact contact))
  1070.   "Return the old-state/new-state for the initial (setf contact-state) after CONTACT
  1071.    is realized. Return nil if (setf contact-state) need not be called, i.e. no
  1072.    initial state transition is necessary."
  1073.   (with-slots (state) contact
  1074.     (when (eq :mapped state)
  1075.       (values :managed :mapped))))
  1076.  
  1077. ;;;-----------------------------------------------------------------------------
  1078. ;;; Contact DESTRUCTION
  1079.  
  1080. ;; Helper function
  1081. (defun map-over-children (contact function &rest args)
  1082.   ;; Apply FUNCTION first to contact's children, then to contact.
  1083.   (when (typep contact 'composite)
  1084.     (dolist (child (composite-children contact))
  1085.       (apply #'map-over-children child function args)))
  1086.   (apply function contact args))
  1087.  
  1088. (defmethod destroy ((contact contact))
  1089.   "Destroy a contact and all its resources"
  1090.   (when (and (not (destroyed-p contact))    ; only destroy windows once
  1091.          (contact-parent contact))        ; Don't destroy root
  1092.     (when (realized-p contact)
  1093.       ;; Turn ON structure-notify to receive destroy-notify events
  1094.       (setf (window-event-mask contact) #.(make-event-mask :structure-notify))
  1095.       ;; Unmap and Destroy the contact's and children's windows.
  1096.       (xlib:destroy-window contact))
  1097.     ;; Destroy resources
  1098.     (map-over-children contact #'destroy-cleanup)
  1099.     ;; unmanage the contact
  1100.     (setf (contact-state contact) :withdrawn)
  1101.     ;; Delete contact from its parent's child list
  1102.     (delete-child (contact-parent contact) contact)
  1103.     ))
  1104.  
  1105. (defun destroy-cleanup (contact)
  1106.   "Deallocate contact resources (gcontexts, fonts, pixmaps etc.)."
  1107.   
  1108.   ;; Mark contact destroyed
  1109.   (setf (window-id contact) -1)
  1110.   
  1111.   ;; Remove contact's timers
  1112.   (delete-timer contact)
  1113.   
  1114.   ;; Destroy the contact's Gcontext when necessary
  1115.   (dolist (gcontext (getf (window-plist contact) 'gcontext-cache))
  1116.     (xlib:free-gcontext gcontext)
  1117.      ;; Debug hack to catch errors
  1118.     #+(and ti (not clos)) (setf (si:array-leader gcontext 1) 'destroyed-gcontext))
  1119.   
  1120.   ;; Ensure modes are popped
  1121.   (delete-mode contact)
  1122.   
  1123.   ;; Destroy a composite's shells
  1124.   (when (typep contact 'composite)
  1125.     (dolist (shell (slot-value (the composite contact) 'shells))
  1126.       (destroy shell)))
  1127.  
  1128.   ;; Invoke any :destroy callback
  1129.   (apply-callback contact :destroy))
  1130.  
  1131. (defun destroy-finish (contact)
  1132.   ;; Called from destroy-notify event processing to remove
  1133.   ;; contact and its descendents from the resource-id hash-table.
  1134.   (map-over-children
  1135.     contact
  1136.     #'(lambda (contact)
  1137.     (xlib::deallocate-resource-id (window-display contact) (window-id contact) 'window)
  1138.     #+(and ti (not clos))
  1139.     (setf (si:array-leader contact 1) 'destroyed-contact) ;; Debug hack to catch errors
  1140.     )))
  1141.  
  1142. ;;;-----------------------------------------------------------------------------
  1143. ;;; ROOT CONTACT
  1144. ;;;
  1145. ;;; For each screen of the display there's a root contact.
  1146. ;;; The root contact is used as the root parent contact for all the contacts
  1147. ;;; on a screen
  1148.  
  1149. (defcontact root (composite)
  1150.   ((screen :type screen :initarg :screen)
  1151.    (pixmap-cache :type list :initform nil)
  1152.    (cursor-cache :type list :initform nil)
  1153.    ;; Zap initforms for window slots.
  1154.    ;; Real values filled in by the :after initialize-instance method.
  1155.    (x :initform 0)
  1156.    (y :initform 0)
  1157.    (width :initform 0)
  1158.    (height :initform 0)
  1159.    (border-width :initform 0)
  1160.    (depth :initform 0)
  1161.    (background :initform :none)
  1162.    )
  1163.   (:resources
  1164.     (focus-name :remove t)
  1165.     (documentation :remove t)
  1166.     ;; Remove all Create-window options
  1167.     (background :remove t)
  1168.     (x :remove t) (y :remove t)
  1169.     (width :remove t) (height :remove t)
  1170.     (depth :remove t)
  1171.     (border-width :remove t)
  1172.     (backing-pixel :remove t)
  1173.     (backing-planes :remove t)
  1174.     (backing-store :remove t)
  1175.     (bit-gravity :remove t)
  1176.     (border :remove t)
  1177.     (class :remove t)
  1178.     (colormap :remove t)
  1179.     (cursor :remove t)
  1180.     (do-not-propagate-mask :remove t)
  1181.     (gravity :remove t)
  1182.     (override-redirect :remove t)
  1183.     (save-under :remove t)
  1184.     (visual :remove t)
  1185.     (screen :remove t)
  1186.     ))
  1187.  
  1188. (defmethod initialize-instance :after ((self root) &rest options)
  1189.   (declare (ignore options))
  1190.   (with-slots
  1191.     (display screen (id xlib:id) x y width height border-width depth initialization)
  1192.     self
  1193.     
  1194.     ;; A root contact represents a root window
  1195.     (setf
  1196.       id             (window-id (screen-root screen))
  1197.       initialization nil            ;; Root window is already realized
  1198.       x              0
  1199.       y              0
  1200.       width          (screen-width screen)
  1201.       height         (screen-height screen)
  1202.       border-width   0
  1203.       depth          (screen-root-depth screen))
  1204.     
  1205.     ;; Update CLX resource id lookup to associate root id with root contact
  1206.     (xlib:save-id display id self)))
  1207.  
  1208. (defun contact-root (contact)
  1209.   ;; Return the root contact associated with CONTACT
  1210.   (declare (type contact contact)
  1211.        (values root))
  1212.   (do* ((parent (contact-parent contact) (contact-parent contact)))
  1213.       ((null parent) contact)
  1214.     (setq contact parent)))
  1215.  
  1216. (defun contact-screen (contact)
  1217.   ;; Return the xlib:screen associated with CONTACT
  1218.   (declare (type contact contact)
  1219.        (values screen))
  1220.   (slot-value (the root (contact-root contact)) 'screen))
  1221.  
  1222. (defun get-pixmap (contact image)
  1223.   "Converts an image into a pixmap resource."
  1224.   (declare (type image image)
  1225.        (type contact contact)
  1226.        (values (or null pixmap)))
  1227.   (let ((root (contact-root contact)))
  1228.     (with-slots ((root-pixmap-cache pixmap-cache) depth) (the root root)
  1229.       (let* ((cache root-pixmap-cache)
  1230.          (pixmap (assoc image cache)))
  1231.     
  1232.     (if pixmap
  1233.         (second pixmap)
  1234.         
  1235.         (if (> depth 1)
  1236.         
  1237.         (progn
  1238.           (using-gcontext (gcontext :drawable root :foreground 1 :background 0) ;; **** WARNING ****
  1239.             (setq pixmap (image-pixmap root image :depth depth :gcontext gcontext)))
  1240.           (push (list image pixmap) root-pixmap-cache)
  1241.           pixmap)
  1242.         
  1243.         (progn
  1244.           (setq pixmap (image-pixmap root image :depth depth))
  1245.           (push (list image pixmap) root-pixmap-cache)
  1246.           pixmap)))))))
  1247.  
  1248. (defun get-cursor (contact number)
  1249.   (declare (type card8 number)
  1250.        (type contact contact)
  1251.        (values (or null pixmap)))
  1252.   (let* ((root (contact-root contact))
  1253.      (cache (slot-value (the root root) 'cursor-cache))
  1254.      (cursor (getf cache number)))
  1255.     (unless cursor
  1256.       (let ((font (open-font (contact-display contact) "cursor")))
  1257.     (setq cursor
  1258.           (create-glyph-cursor
  1259.         :source-font font
  1260.         :source-char number
  1261.         :mask-font font
  1262.         :mask-char (1+ number)
  1263.         :foreground (make-color :red 0.0 :green 0.0 :blue 0.0)
  1264.         :background (make-color :red 1.0 :green 1.0 :blue 1.0))))
  1265.       (setf (slot-value (the root root) 'cursor-cache)
  1266.         (list* number cursor cache)))
  1267.     cursor))
  1268.  
  1269.  
  1270.  
  1271.  
  1272. ;;;-----------------------------------------------------------------------------
  1273. ;;; STREAM SUPPORT
  1274.  
  1275. ;;; PHILOSOPHY
  1276. ;;;
  1277. ;;; CLUE keeps a single character buffer for all windows, instead of a
  1278. ;;; separate buffer for every window.  The reason its done this way is
  1279. ;;; to prevent focus management problems within an application.  We
  1280. ;;; reason that a single application will use a single display (or one
  1281. ;;; display per process), and that when users type on the keyboard,
  1282. ;;; they're typing to the APPLICATION, not to a (sub)widow of an
  1283. ;;; application.  In particular, users shouldn't have to care about
  1284. ;;; keyboard focus within an application.
  1285. ;;;
  1286. ;;; If there are several stream contacts for a particular display
  1287. ;;; (server connection) then the contact getting keystrokes is the
  1288. ;;; contact that's doing the read.  With a single buffer there's no need
  1289. ;;; to worry about where the mouse is within the application, or which
  1290. ;;; window has the keyboard focus.  The user is never left typing
  1291. ;;; into a dead window, only to have the buffered key events appear
  1292. ;;; later when the keyboard focus changes.
  1293.  
  1294. (defun read-character (display &optional timeout)
  1295.   "Enters an input loop which can be exited whenever a character is
  1296.    available in the display keyboard buffer. The function's return value
  1297.     is the next char from this buffer."
  1298.   (or (pop (display-keyboard-buffer display))
  1299.       (loop
  1300.     (process-next-event display timeout)
  1301.     (let ((char (pop (display-keyboard-buffer display))))
  1302.       (when (or char timeout)
  1303.         (return char))))))
  1304.  
  1305. (defun unread-character (display character)
  1306.   "Make CHARACTER be the next character returned from GET-CHARACTER"
  1307.   (push character (display-keyboard-buffer display)))
  1308.  
  1309. (defun listen-character (display &optional (timeout 0))
  1310.   "If a character is available within TIMEOUT seconds, return it without
  1311.     removing it from the display keyboard buffer. Otherwise return NIL."
  1312.   (let ((char (read-character display timeout)))
  1313.     (when char
  1314.       (unread-character display char)
  1315.       char)))
  1316.  
  1317. (defun append-characters (display character &optional (start 0) end)
  1318.   "Put a character or string in the display keyboard buffer"
  1319.   (declare (type display display)
  1320.        (type (or string-char string) character))
  1321.   ;; When event-handlers return a character or string, stuff it into the keyboard buffer
  1322.   (etypecase character
  1323.     (character (setf (display-keyboard-buffer display)
  1324.              (nconc (display-keyboard-buffer display) (cons character nil))))
  1325.     (string
  1326.      (do ((i start (1+ i))
  1327.       (end (or end (length character))))
  1328.      ((>= i end))
  1329.        (setf (display-keyboard-buffer display)
  1330.          (nconc (display-keyboard-buffer display) (cons (char character i) nil)))))))
  1331.  
  1332. (defun clear-characters (display)
  1333.   "Clear the display keyboard buffer"
  1334.   (declare (type display display))
  1335.   (setf (display-keyboard-buffer display) nil))
  1336.  
  1337.  
  1338. ;;;-----------------------------------------------------------------------------
  1339. ;;; GEOMETRY MANAGEMENT
  1340.  
  1341. (defmethod add-child ((self composite) contact &key)
  1342.   "Put CONTACT on its parent's list of managed contacts"
  1343.   ;; Default is to put at end of list
  1344.   (with-slots ((manager-children children)) self
  1345.     (let ((children manager-children))
  1346.       (unless (member contact children :test #'eq)
  1347.     (setf manager-children (nconc children (cons contact nil)))))))
  1348.  
  1349. (defmethod delete-child ((self composite) contact &key)
  1350.   "Remove CONTACT from the list of contacts"
  1351.   (with-slots ((manager-children children)) self
  1352.     (setf manager-children (delete contact manager-children))))
  1353.  
  1354. ;; Utility functions for geometry management
  1355. (defun previous-sibling (contact)
  1356.   "Return the first managed contact BEFORE CONTACT"
  1357.   (let ((previous nil))
  1358.     (dolist (sibling (composite-children (contact-parent contact)))
  1359.       (when (eq sibling contact) (return previous))
  1360.       (when (managed-p sibling) (setq previous sibling)))))
  1361.  
  1362. (defun next-sibling (contact)
  1363.   "Return the first managed contact AFTER CONTACT"
  1364.   (dolist (sibling (cdr (member contact (composite-children (contact-parent contact)) :test #'eq)))
  1365.     (when (managed-p sibling) (return sibling))))
  1366.  
  1367. (defun change-priority (contact priority &key sibling accept-p)
  1368.   "Change CONTACT's stacking order"
  1369.   (declare (type contact contact)
  1370.        (type (member :above :below :top-if :bottom-if :opposite) priority)
  1371.        (type (or null contact) sibling)
  1372.        (values success-p priority sibling))
  1373.   (when (realized-p contact) ;; Don't mess with priority when not realized
  1374.     (let ((accept-p (or accept-p (top-level-p contact))))
  1375.       (multiple-value-bind (success-p new-priority new-sibling)
  1376.       (manage-priority (contact-parent contact) contact priority sibling)
  1377.     (when (or success-p accept-p)
  1378.       (setf (window-priority contact sibling) priority))
  1379.     (values success-p new-priority new-sibling)))))
  1380.  
  1381. (defmethod manage-priority ((self composite) contact priority sibling &key)
  1382.   "Change the stacking order of CONTACT relative to SIBLING.
  1383.    PRIORITY is one of :above :below :top-if :bottom-if :opposite."
  1384.   (declare (type (member :above :below :top-if :bottom-if :opposite) priority)
  1385.        (type (or null contact) sibling)
  1386.        (values success-p priority sibling))
  1387.   self contact ;; not used
  1388.   (values t priority sibling))
  1389.  
  1390. (defmethod accept-focus-p ((contact contact))
  1391.   "Returns non-nil when CONTACT is willing to become the keyboard input focus"
  1392.   (declare (values boolean))
  1393.   (and (visible-p contact)
  1394.        (plusp (logand (contact-event-mask contact)
  1395.               #.(make-event-mask :key-press :key-release)))))
  1396.  
  1397. (defmethod move-focus ((composite composite) &optional (direction :next) &key start revert-to)
  1398.   "Move the input focus to the :next :previous or :set contact from START.
  1399.  START defaults to the current focus if there is one, or the first child.
  1400.  Returns the new focus contact or NIL if no contacts will accept the
  1401.  focus (see accept-focus-p)."
  1402.   (declare (type (member :next :previous :set) direction)
  1403.        (type (or null contact) start)
  1404.        (values (or null focus-contact)))
  1405.  
  1406.   (let* ((start (or start (composite-focus composite)))
  1407.      (focus (or start (first (composite-children composite)))))
  1408.     
  1409.     (when focus ;; focus nil when composite has no children
  1410.       (assert (member focus (composite-children composite) :test #'eq) ()
  1411.           "~s isn't a child of ~s" focus composite)
  1412.       (when
  1413.     (setf focus
  1414.           (if (eq :set direction)
  1415.           ;; Ensure requested focus is ready to accept
  1416.           (when (accept-focus-p focus) focus)          
  1417.  
  1418.           ;; Else look for next focus ready to accept
  1419.           (do* ((get-sibling (ecase direction (:next 'next-sibling) (:previous 'previous-sibling)))
  1420.             (focus       (funcall get-sibling focus) (funcall get-sibling focus)))               
  1421.                ((or (not focus) (eq focus start)))
  1422.             (when (accept-focus-p focus) (return focus)))))
  1423.     
  1424.     ;; Tell server to change input focus
  1425.     (set-input-focus (contact-display focus) focus (or revert-to :parent)))
  1426.  
  1427.       ;; Record focus child found
  1428.       (setf (slot-value (the composite composite) 'focus) focus))))
  1429.  
  1430.  
  1431. (defmethod preferred-size ((contact contact) &key width height border-width)
  1432.   "Return preferred size, based on given changes to current values."
  1433.   (declare (values width height border-width))
  1434.   ;; Primary method is compliant
  1435.   (with-slots ((current-width width)
  1436.            (current-height height)
  1437.            (current-border-width border-width)) contact
  1438.     (values (or width current-width)
  1439.         (or height current-height)
  1440.         (or border-width current-border-width))))
  1441.  
  1442.  
  1443. (defun change-geometry (contact &key x y width height border-width accept-p)
  1444.   "Geometry management.  Nil values indicate parameters the geometry manager can change at will.
  1445.    Returns T when the request is granted, NIL when refused or NIL x y width height border-width
  1446.    when a compromise is offered. When ACCEPT-P, always take the geometry manager's compromise."
  1447.   (declare (type contact contact)
  1448.        (type (or null int16) x y)
  1449.        (type (or null card16) width height border-width)
  1450.        (type boolean accept-p)
  1451.        (values success-p x y width height border-width))
  1452.   (unless (destroyed-p contact)
  1453.     (let ((accept-p (or accept-p (top-level-p contact))))
  1454.       (with-slots ((contact-x x)
  1455.            (contact-y y)
  1456.            (contact-width width)
  1457.            (contact-height height)
  1458.            (contact-border-width border-width)
  1459.            (contact-parent parent)) (the basic-contact contact)
  1460.     (multiple-value-bind (success-p x1 y1 width1 height1 border-width1)
  1461.         (if (managed-p contact)
  1462.         (manage-geometry contact-parent contact x y width height border-width)
  1463.         (values t
  1464.             (or x contact-x) (or y contact-y)
  1465.             (or width contact-width) (or height contact-height)
  1466.             (or border-width contact-border-width)))
  1467.       (if (or success-p (and accept-p x1))
  1468.           (xlib:with-state (contact)
  1469.         (unless success-p ;; Accept a compromise geometry
  1470.           (unless (manage-geometry contact-parent contact x1 y1 width1 height1 border-width1)
  1471.             (error "manage-geometry failed to accept its own compromise geometry")))
  1472.         (when (or (not (= contact-x x1))
  1473.               (not (= contact-y y1)))
  1474.           (move contact x1 y1))
  1475.         (when (or (not (= contact-width width1))
  1476.               (not (= contact-height height1))
  1477.               (not (= contact-border-width border-width1)))
  1478.           (resize contact width1 height1 border-width1))))
  1479.  
  1480.       (values success-p x1 y1 width1 height1 border-width1))))))
  1481.  
  1482. (defparameter *contact-notified* nil) ;; NIL outside without-requests
  1483.  
  1484. (defmacro without-requests (contact &body body)
  1485.   "Any server requests on CONTACT ordinarily sent within BODY should be skipped.
  1486. This wrapper is used when CONTACT needs to update its state to reflect window changes
  1487. already performed by the user/wm."
  1488.   `(let ((*contact-notified* ,contact)) ,@body))
  1489.  
  1490. (defmethod move ((contact contact) x y)
  1491.   "Move CONTACT to coordinates X/Y relative to its parent."
  1492.   (with-slots ((contact-x x) (contact-y y)) contact
  1493.     (unless (eq contact *contact-notified*)
  1494.       (when (realized-p contact)
  1495.     (unless (= contact-x x) (setf (xlib:drawable-x contact) x))
  1496.     (unless (= contact-y y) (setf (xlib:drawable-y contact) y))))
  1497.     (setf contact-x x)
  1498.     (setf contact-y y)))
  1499.   
  1500. (defmethod resize ((contact contact) width height border-width)
  1501.   "Change the size of CONTACT."
  1502.   (with-slots ((contact-width width)
  1503.            (contact-height height)
  1504.            (contact-border-width border-width)) contact
  1505.     (unless (eq contact *contact-notified*)
  1506.       (when (realized-p contact)
  1507.     (unless (= contact-width width)
  1508.       (setf (xlib:drawable-width contact) width))
  1509.     (unless (= contact-height height)
  1510.       (setf (xlib:drawable-height contact) height))
  1511.     (unless (= contact-border-width border-width)
  1512.       (setf (xlib:drawable-border-width contact) border-width))))
  1513.     (setf contact-width width)
  1514.     (setf contact-height height)
  1515.     (setf contact-border-width border-width)))
  1516.  
  1517. (defconstant *default-contact-height* 16)
  1518. (defconstant *default-contact-width* 16)
  1519.  
  1520. (defmethod manage-geometry ((parent composite) contact x y width height border-width &key)  
  1521.   (declare (type contact contact)
  1522.        (type (or null int16) x y)
  1523.        (type (or null card16) width height border-width)
  1524.        (values success-p x y width height border-width))
  1525.   (with-slots ((contact-x x)
  1526.            (contact-y y)
  1527.            (contact-width width)
  1528.            (contact-height height)
  1529.            (contact-border-width border-width)) (the contact contact)
  1530.  
  1531.     ;; Just ensure positive size
  1532.     (let* ((requested-width   (or width contact-width))
  1533.        (acceptable-width  (if (zerop requested-width)
  1534.                   *default-contact-width*
  1535.                   requested-width))
  1536.        (requested-height  (or height contact-height))
  1537.        (acceptable-height (if (zerop requested-height)
  1538.                   *default-contact-height*
  1539.                   requested-height)))
  1540.       
  1541.       (values (and (= requested-width acceptable-width)
  1542.            (= requested-height acceptable-height))
  1543.           (or x contact-x)
  1544.           (or y contact-y)
  1545.           acceptable-width
  1546.           acceptable-height        
  1547.           (or border-width contact-border-width)))))
  1548.  
  1549.  
  1550. ;;; change-layout should be called whenever the set of managed children for the
  1551. ;;; composite is changed.  Its purpose is to update children geometries for the new
  1552. ;;; managed set.  The newly-managed argument, if given, would the child which is now
  1553. ;;; being added to the managed set.  (The change-layout algorithm might use this in
  1554. ;;; enforcing constraints, perhaps to put the squeeze on the new guy rather than on
  1555. ;;; the previously-managed set).  This method, like manage-geometry, is never called
  1556. ;;; by application programmers and rarely called by contact programmers, but must be
  1557. ;;; provided by the composite programmer in order to implement the composite's gmgmt
  1558. ;;; policy.
  1559.  
  1560. ;;; Most composites will probably want to over-ride this
  1561. (defmethod change-layout ((composite composite) &optional newly-managed)
  1562.   "Called whenever the set of managed children changes."
  1563.   (declare (type (or null contact) newly-managed))
  1564.   (if newly-managed
  1565.       (change-geometry newly-managed :accept-p t)
  1566.       (dolist (child (composite-children composite))
  1567.     (change-geometry child :accept-p t))))
  1568.  
  1569.  
  1570.  
  1571.